﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO;
using System.Runtime.InteropServices;

namespace DecompressHeightMap
{
    class Program
    {
        static void Main(string[] args)
        {
            int offset = 0;
            FileStream fileStream = new FileStream(@"D:\swords\client\maps\x63\x63_1.t2bk", FileMode.Open, FileAccess.Read, FileShare.Read);

            TRN2FILEIDVER IdVer = new TRN2FILEIDVER();
            byte[] ver = new byte[Marshal.SizeOf(IdVer)];
            fileStream.Read(ver, 0, ver.Length);
             IdVer = Deserialize<TRN2FILEIDVER>(ver);

            int iNumBlock = 0;
            int m_byBlockComp = 0;		//	Block data flag

            if (IdVer.dwVersion < 2)
            {
                T2BKFILEHEADER Header = new T2BKFILEHEADER();
                byte[] head = new byte[Marshal.SizeOf(Header)];
                fileStream.Read(head, 0, head.Length);
                Header = Deserialize<T2BKFILEHEADER>(head);

                iNumBlock = Header.iNumBlock;
                m_byBlockComp = 0;
            }
            else if (IdVer.dwVersion < 5)
            {
                T2BKFILEHEADER2 Header = new T2BKFILEHEADER2();
                byte[] head = new byte[Marshal.SizeOf(Header)];
                fileStream.Read(head, 0, head.Length);
                Header = Deserialize<T2BKFILEHEADER2>(head);

                iNumBlock = Header.iNumBlock;
                m_byBlockComp = Header.bCompressed ? (byte)(flags.T2BKCOMP_COL_ZIP | flags.T2BKCOMP_HEI_ZIP | flags.T2BKCOMP_NOR_ZIP) : (byte)0;
            }
            else
            {
                T2BKFILEHEADER5 Header = new T2BKFILEHEADER5();
                byte[] head = new byte[Marshal.SizeOf(Header)];
                fileStream.Read(head, 0, head.Length);
                Header = Deserialize<T2BKFILEHEADER5>(head);

                iNumBlock = Header.iNumBlock;
                m_byBlockComp = Header.byCompressed;
            }

            List<int> m_aBlockOffs = new List<int>();
            for (int i = 0; i < iNumBlock; i++)
            {
                byte[] block = new byte[4];
                fileStream.Read(block, 0, block.Length);

                // 调整字节顺序
                //if (BitConverter.IsLittleEndian)
                //    Array.Reverse(block);

                // 另一种转换方式
                /*int value = (int)((block[0] & 0xFF)
                    | ((block[1] & 0xFF) << 8)
                    | ((block[2] & 0xFF) << 16)
                    | ((block[3] & 0xFF) << 24));*/

                m_aBlockOffs.Add(BitConverter.ToInt32(block, 0));
            }
        }

        public static byte[] Serialize<T>(T obj)
        {
            int rawsize = Marshal.SizeOf(obj);
            IntPtr buffer = Marshal.AllocHGlobal(rawsize);
            Marshal.StructureToPtr(obj, buffer, false);
            byte[] rawdatas = new byte[rawsize];
            Marshal.Copy(buffer, rawdatas, 0, rawsize);
            Marshal.FreeHGlobal(buffer);
            return rawdatas;
        }

        public static T Deserialize<T>(byte[] rawdatas)
        {
            Type anytype = typeof(T);
            int rawsize = Marshal.SizeOf(anytype);
            if (rawsize > rawdatas.Length) return default(T);

            IntPtr buffer = Marshal.AllocHGlobal(rawsize);
            Marshal.Copy(rawdatas, 0, buffer, rawsize);
            object retobj = Marshal.PtrToStructure(buffer, anytype);
            Marshal.FreeHGlobal(buffer);

            return (T)retobj;
        }
    }
}
